package mobi.zeedev.flyingsaucer.scala.regex

import util.matching.Regex
import mobi.zeedev.flyingsaucer.common.RegexModule.interfaces.IRegexQueries
import mobi.zeedev.flyingsaucer.common.WebQueryModule.interfaces.IResult
import mobi.zeedev.flyingsaucer.common.RegexModule.impl.{ParseException, RegexQueries}
import mobi.zeedev.flyingsaucer.common.DataModule.tree.{DatabaseType, DatabaseTree}
import java.lang.Boolean

//import java.util.{ArrayList, HashMap, List, Map}

import mobi.zeedev.flyingsaucer.common.DataModule.{BeerConstants, MetaBeer}
import mobi.zeedev.flyingsaucer.common.CredentialsModule.impl.HomeInfo
import mobi.zeedev.flyingsaucer.common.RegexModule.RegexUtil

/**
 * User: James
 * Date: 1/17/11
 * Time: 6:48 PM
 */

class ScalaRegexQueries extends IRegexQueries {

  @throws(classOf[ParseException])
  override def getTastedUntastedPage(result: IResult): java.util.List[java.util.Map[String, Object]] = {

    //    val ret = new ArrayList[Map[String, Object]]()

    val data: String = result.getContent

    val outerRegex: Regex = new Regex("(?s)" + RegexQueries.REGEX_TASTED_OUTER, "innerSection")
    val innerRegex: Regex = new Regex(RegexQueries.REGEX_TASTED_INNER, "beerId", "property", "value")


    val outerResult = outerRegex.findAllIn(data).matchData.map(_.group("innerSection"))
    val innerResult = outerResult.map(innerRegex.findAllIn(_).matchData).map(
      _.foldLeft(new java.util.HashMap[String, Object]())(
        (acc, cur) => {
          acc.put(MetaBeer.BEER_ID, cur.group("beerId"))
          cur match {

            case cur if cur.group("property") == "name" => {
              RegexUtil.addNameProperties(RegexUtil.stripSlashes(cur.group("value")), acc);
              acc
            }
            case _ => {
              acc.put(cur.group("property"), RegexUtil.stripSlashes(cur.group("value")));
              acc
            }

          }
        }


      )).toList






    scala.collection.JavaConversions.asList(innerResult)

    //    innerResult

  }

  //  def addNamePropertiesHelper(value: String): scala.collection.immutable.List[(String, Object)] = {
  //    val map: Map[String, Object] = new HashMap[String, Object]()
  //    RegexUtil.addNameProperties(value, map)
  //    map.toList
  //  }

  @throws(classOf[ParseException])
  override def getMemberPage(result: IResult): java.lang.Integer = {

    val data: String = result.getContent

    val memberIdReg = RegexQueries.REGEX_PROFILE.r

    val regValue = memberIdReg.findFirstIn(data) match {
      case Some(memberIdReg(x)) => Some(x)
      case _ => None
    }

    //    val regResult = memberIdReg.findAllIn(data).matchData.toList.head.subgroups(0)

    //TODO ERROR HANDLING HERE SOMEWHERE

    val memberId: java.lang.Integer = regValue match {
      case Some(x) => x.toInt
      case None => null
    }
    //      regResult match {
    //      case Some(x) => x.toInt
    //      case None => null
    //    }

    memberId

  }

  @throws(classOf[ParseException])
  override def getLoginMain(result: IResult): HomeInfo = {

    var hi: HomeInfo = new HomeInfo()

    val regString: List[Any] = RegexQueries.PAGE_MAIN_A :: new Regex(RegexQueries.PAGE_MAIN_B, "welcomeText", "name") :: RegexQueries.PAGE_MAIN_C :: RegexQueries.PAGE_MAIN_D :: Nil

    val reges: List[Regex] = regString.map(m => m match {
      case m: String => m.r
      case m: Regex => m
    })

    val regResults = reges.map(_.findAllIn(result.getContent).matchData).map(_.foldLeft(scala.collection.immutable.List[Any]())(
      (accList, m) => m match {
        case m if m.groupNames.contains("welcomeText") => (HomeInfo.WELCOME_BACK_NAME_WEB, m.subgroups(1)) :: accList
        case m if m.groupCount == 2 => (m.subgroups(0), m.subgroups(1)) :: accList
        case m if m.groupCount == 4 => (m.subgroups(0), m.subgroups(1)) :: (m.subgroups(2), m.subgroups(3)) :: accList
      }
    ).toList).toList

    val loginResult: scala.collection.immutable.Map[String, String] = regResults.flatten.map(cur => cur match {
      case (x, y) => (x.toString, y.toString)
    }).toMap

    //    println(loginResult)




    for (curk <- loginResult.keySet) {
      if (curk.equals(HomeInfo.PLATE_CURRENT_TOTAL_WEB)) {
        hi.put(HomeInfo.PLATE_CURRENT_TOTAL, loginResult.get(curk).getOrElse(null))
      }
      else if (curk.equals(HomeInfo.PLATE_REQUIRED_TOTAL_WEB)) {
        hi.put(HomeInfo.PLATE_REQUIRED_TOTAL, loginResult.get(curk).getOrElse(null))
      }
      else if (curk.equals(HomeInfo.E_MAIL_WEB)) {
        hi.put(HomeInfo.E_MAIL, loginResult.get(curk).getOrElse(null))
      }
      else if (curk.equals(HomeInfo.WELCOME_BACK_NAME_WEB)) {
        hi.put(HomeInfo.WELCOME_NAME, loginResult.get(curk).getOrElse(null))
      }
      else {
        hi.put(curk, loginResult.get(curk).getOrElse(null))
      }
    }




    hi
  }

  @throws(classOf[ParseException])
  override def getStoresURLs(result: IResult): java.util.Map[String, String] = {

    val ret = new java.util.HashMap[String, String]()

    val htmlContent: String = result.getContent

    val storeToUrlReg = new Regex("(?s)" + RegexQueries.REGEX_LOGIN_STORE_URLS, "storeKey", "partialUrl")
    val storeNameToIdMapReg = new Regex(RegexQueries.REGEX_LOGIN_STORES, "storeId", "storeName")

    val MapStoreKeyUrl = storeToUrlReg.findAllIn(htmlContent).matchData.map(m => (m.subgroups(0), m.subgroups(1))).toMap
    val MapStoreIdStoreName = storeNameToIdMapReg.findAllIn(htmlContent).matchData.map(m => (m.subgroups(0), m.subgroups(1))).toMap


    for (curStoreKey <- MapStoreKeyUrl.keys) {
      for (curStoreName <- MapStoreIdStoreName.values) {
        if (curStoreName.toLowerCase.replaceAll(" ", "").contains(curStoreKey)) {
          val storeUrl: Option[String] = MapStoreKeyUrl.get(curStoreKey.toString)
          storeUrl match {
            case Some(storeUrlActual) => ret.put(curStoreName, storeUrlActual)
            case _ =>
          }
        }
      }
    }

    ret

  }

  @throws(classOf[ParseException])
  override def getStoresTree(result: IResult): DatabaseTree = {

    val htmlContent = result.getContent

    val tree: DatabaseTree = new DatabaseTree()

    //TODO HACK
    tree.addTable("stores")

    val storeToUrlReg = new Regex("(?s)" + RegexQueries.REGEX_LOGIN_STORE_URLS, "storeKey", "partialUrl")
    val storeNameToIdMapReg = new Regex(RegexQueries.REGEX_LOGIN_STORES, "storeId", "storeName")

    val MapUrlStoreKey = storeToUrlReg.findAllIn(htmlContent).matchData.map(m => (m.subgroups(1), m.subgroups(0))).toMap
    val ListStoreIdStoreName: List[(String, String)] = storeNameToIdMapReg.findAllIn(htmlContent).matchData.map(m => (m.subgroups(0), m.subgroups(1))).toList


    ListStoreIdStoreName
      .foreach(
      m => m match {
        case (storeId, storeName) => tree.addPrimaryKey("storeName", storeName).addAttribute("storeNumber", storeId)
      }

    )


    for (curNode <- scala.collection.JavaConversions.asIterable(tree)) {
      if (curNode.getType() == DatabaseType.PRIMARY_KEY) {
        val convertedKey: String = "/stores/" + ConvertStoreNameUrlName(curNode.getValue.toString) + "/"

        if (MapUrlStoreKey.get(convertedKey) != None) {
          val url: String = BeerConstants.BEERKNURD_URL_ROOT + convertedKey + "beer"
          curNode.addAttribute("storeUrl", url)
          curNode.addAttribute("storeUrlName", convertedKey)
        }
      }

    }




    tree

  }

  def ConvertStoreNameUrlName(storeName: String): String = {
    if (storeName == null) {
      return null
    }
    var ret: String = storeName.replace("Flying Saucer", "").replace(" ", "").toLowerCase
    return ret
  }

  @throws(classOf[ParseException])
  override def getStoresBeersByName(result: IResult): java.util.Map[String, Object] = {

    //    val ret = Map[String, Object]()

    val nameRegex: Regex = new Regex(RegexQueries.REGEX_STORES_OPTION, "beerId", "nameProperties")

    val regexResults = nameRegex.findAllIn(result.getContent).matchData.foldLeft(new java.util.HashMap[String, Object]())(
      (acc, m) => {
        RegexUtil.addNameProperties(m.group("nameProperties"), acc)
        acc.put(MetaBeer.BEER_ID, m.group("beerId"))
        acc
      }
    )



    regexResults

  }

  @throws(classOf[ParseException])
  override def getStoresBeersByCategory(result: IResult): java.util.List[java.util.Map[String, Object]] = {

    val outerReg: Regex = new Regex("(?s)" + RegexQueries.REGEX_STORES_OPTGROUP, "void", "subSection")
    val innerReg: Regex = new Regex(RegexQueries.REGEX_STORES_OPTION, "beerId", "nameProperties")

    val outerResults = outerReg.findAllIn(result.getContent).matchData.foldLeft(List[scala.collection.mutable.HashMap[String, Object]]())(
      (accOuter, matchOuter) => {
        val children = innerReg.findAllIn(matchOuter.group("subSection")).matchData.foldLeft(List[scala.collection.mutable.HashMap[String, Object]]())(
          (accInnerChildren, matchInnerChildren) => {
            val innerMap = scala.collection.mutable.HashMap[String, Object]()
            //            val innerMap = new HashMap[String,Object]()
            innerMap.put(MetaBeer.BEER_ID, matchInnerChildren.group("beerId"))
            RegexUtil.addNameProperties(matchInnerChildren.group("nameProperties"), scala.collection.JavaConversions.asMap(innerMap))
            //            innerMap :: acc
            //            acc.add(innerMap)
            //            println("nameProperties: " + matchInnerChildren.group("nameProperties"))
            //            println("innerMap" + innerMap)
            innerMap :: accInnerChildren
          }

        )


        if (children.size > 0) {


          children.foldLeft(List[scala.collection.mutable.HashMap[String, Object]]())((accInner, child) => {
            child.put("Void", matchOuter.group("void"))
            child :: accInner
          }) ::: accOuter

        } else {

          accOuter
        }
      }
    )

    //    println("outerResults: " + outerResults)


    //    outerResults.map(_.asInstanceOf[java.util.Map[String,Object]]).asInstanceOf[java.util.List[java.util.Map[String,Object]]]
    //       outerResults.map(_.asInstanceOf[java.util.Map[String,Object]]).asInstanceOf[java.util.List[java.util.Map[String,Object]]]
    scala.collection.JavaConversions.asList(outerResults.map(scala.collection.JavaConversions.asMap(_)))
  }

  @throws(classOf[ParseException])
  def detectIncorrectLogin(result: IResult): Boolean = {
    var ret: Boolean = true
    if (result != null && result.getContent != null && result.getContent.length > 0) {
      ret = result.getContent.contains(RegexQueries.INCORRECT_LOGIN_MARKER) || result.getContent.contains(RegexQueries.INCORRECT_LOGIN_MARKER_STORE_NUMBER) ||
      result.getContent.contains(RegexQueries.INCORRECT_LOGIN_MARKER_STORE_SELECT)

    } else {
      throw new ParseException("Could not parse page for incorrect login.")
    }


    ret

  }
}